package com.dly.blog.service.impl;

import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.dly.blog.domain.File;
import com.dly.blog.domain.ro.FileRO;
import com.dly.blog.domain.vo.FileVO;
import com.dly.blog.enums.FileState;
import com.dly.blog.enums.UploadPermissions;
import com.dly.blog.enums.UploadType;
import com.dly.blog.exception.FileExceptionEnum;
import com.dly.blog.plugin.UploadFilePlugin;
import com.dly.blog.queue.OverdueFileQueue;
import com.dly.blog.service.FileService;
import com.dly.blog.mapper.FileMapper;
import com.dly.blog.utile.JwtService;
import com.google.common.collect.Lists;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import jakarta.servlet.ServletOutputStream;
import jakarta.servlet.http.HttpServletResponse;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.springframework.http.MediaType;
import org.springframework.plugin.core.PluginRegistry;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Objects;

/**
* @author qq215
* @description 针对表【blog_file】的数据库操作Service实现
* @createDate 2023-07-11 22:24:39
*/
@Service
@Slf4j
@AllArgsConstructor
public class FileServiceImpl extends ServiceImpl<FileMapper, File>
    implements FileService{

    private final PluginRegistry<UploadFilePlugin, UploadType> pluginRegistry;

    private final JwtService jwtService;

    private final OverdueFileQueue overdueFileQueue;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public FileVO save(FileRO fileRo) {
        final FileVO fileVo = new FileVO();
        final ArrayList<String> urls = Lists.newArrayList();
        final List<File> files = new ArrayList<>();

        for (MultipartFile file : fileRo.getMultipartFiles()) {
            File fileInfo = new File();
            fileInfo.setFileName(file.getOriginalFilename());
            fileInfo.setFileType(file.getContentType());
            fileInfo.setFilePath(getFullPath());
            fileInfo.setFileSize(file.getSize());
            //文件类型，就是文件用来干嘛的
            fileInfo.setFileClazz(fileRo.getFileType());
            //上传类型
            fileInfo.setUploadType(fileRo.getUploadType());
            if(Objects.isNull(fileRo.getFileType())){
                throw FileExceptionEnum.NOT_SUPPORTED_FILE_UPLOAD.getFileException();
            }
            String fullPath = getFullPath();
            pluginRegistry.getPluginFor(fileRo.getUploadType()).ifPresent(uploadFilePlugin -> uploadPermissions(uploadFilePlugin, fileRo, fileInfo, fullPath, file));
            files.add(fileInfo);
            urls.add(fileInfo.getUrl());
        }

        this.saveBatch(files);

        fileVo.setFileIds(files.stream().map(File::getId).toList());
        fileVo.setTokenUrls(urls);
        return fileVo;
    }

    public void uploadPermissions(UploadFilePlugin uploadFilePlugin, FileRO fileRO, File fileInfo, String fullPath, MultipartFile file){
        switch (fileRO.getUploadPermissions()){
            case PUBLIC -> {
                fileInfo.setExpirationDate(-1);
                uploadFilePlugin.uploadFile(fileInfo, fullPath, file);
            }
            case PRIVATE -> {
                if(Objects.isNull(fileRO.getExpirationDate())){
                    throw FileExceptionEnum.FILE_EXPIRATION.getFileException();
                }
                //设置过期时间
                fileInfo.setExpirationDate(fileRO.getExpirationDate());
                uploadFilePlugin.uploadFileTerm(fileInfo, fullPath, file);
                //添加到延时队列
                overdueFileQueue.addFile(fileInfo.getId(), fileRO.getExpirationDate());
            }

        }
    }

    @Override
    public void fileIdLoad(HttpServletResponse response, String fileId) {
        try {
            //一定要在文件放入输出流之前
            //response.setContentType("image/png");
            File file = this.getById(fileId);
            ServletOutputStream outputStream = response.getOutputStream();
            FileUtils.copyFile(new java.io.File(file.getFilePath()), outputStream);
            outputStream.flush();
            outputStream.close();
        }catch (Exception e){
            log.debug(" 文件不存在 {}",e.getMessage());
            throw FileExceptionEnum.FILE_NOT_EXIT.getFileException();
        }
    }

    @Override
    public void fileTokenLoad(HttpServletResponse response, String token) {
        String fileId = jwtService.unSignFile(token);
        if(Objects.isNull(fileId)){
            throw FileExceptionEnum.FILE_OVERDUE.getFileException();
        }
        fileIdLoad(response, fileId);
    }


    @Override
    public void reviseFile(String id) {
        baseMapper.reviseFile(id);
    }

    /**
     * @Author linyu.dai
     * @Description 获取文件路径
     * @Date 2022/11/7 11:11
     * @Param []
     * @return java.lang.String
     */
    public String getFullPath() {
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
        String format = simpleDateFormat.format(new Date());
        return StringPool.SLASH + format + StringPool.SLASH;
    }
}




